package edu.byu.intex2.data.dao;

import edu.byu.intex2.data.dao.*;
import java.sql.*;
import java.util.*;

/*******************************************************************************
 *
 *        @author Adam
 *          Date: Mar 3, 2009
 *   Description:
 * Last Revision: Mar 3, 2009
 *
 ******************************************************************************/

public class TaskCCDAO {

   /////////////////////////////////////////////
    ///   Singleton code
    private static TaskCCDAO instance = null;

    /** Creates a new instance of TaskCCDAO */
    private TaskCCDAO() {
    }//constructor

    /** Retrieves the single instance of this class */
    public static synchronized TaskCCDAO getInstance() {
        if (instance == null) {
            instance = new TaskCCDAO();
            }
        return instance;
    }//getInstance

    ////////////////////////////////////////////
    ///   CREATE methods
    /** Creates a new TaskCC in the database */
    public TaskCC create(String ID) throws DataException {
        TaskCC tcc = new TaskCC(ID);
        tcc.setObjectAlreadyInDB(false);
        Cache.getInstance().put(tcc.getId(), tcc);
        return tcc;
    }//create

    ////////////////////////////////////////////
    ///   READ methods
    /** Reads an existing TaskCC from the database */
    public TaskCC read(String ID) throws DataException {
        if (Cache.getInstance().containsKey(ID)) {
            return (TaskCC)Cache.getInstance().get(ID);
        }
        Connection conn = ConnectionPool.getInstance().get();
        try {
            return read(ID, conn);
        }catch (Exception e) {
            throw new DataException("An error occurred while reading the business object information.", e);
        }finally {
            ConnectionPool.getInstance().release(conn);
        }
    }

    /** Internal method to read an existing TaskCC from the database */
    synchronized TaskCC read(String ID, Connection conn) throws Exception {

        if (Cache.getInstance().containsKey(ID)) {
            return (TaskCC)Cache.getInstance().get(ID);
        }
        PreparedStatement stmt = conn.prepareStatement("SELECT * FROM Task_CC WHERE ID=?");
        try{
            stmt.setString(1, ID);
            ResultSet rs = stmt.executeQuery();
            if (rs.next()) {
                return readRecord(rs, conn);
            }//if
            throw new DataException("TaskCC with id '" + ID + "' not found.");
        }finally{
            stmt.close();
        }
    }//read

    /** Internal method to create a TaskCC object from a record */
    synchronized TaskCC readRecord(ResultSet rs, Connection conn) throws Exception {
        if (Cache.getInstance().containsKey(rs.getString("ID"))) {
            return (TaskCC)Cache.getInstance().get(rs.getString("ID"));
        }
        TaskCC tcc = new TaskCC(rs.getString("ID"));
        tcc.setObjectAlreadyInDB(true);
        Cache.getInstance().put(tcc.getId(), tcc);
        tcc.setLabortime(rs.getDouble("labortime"));
        tcc.setTaskID(rs.getString("ID"));
        tcc.setConcCarID(rs.getString("ID"));
        tcc.setDirty(false);

        return tcc;
    }//readRecord

    /////////////////////////////////////////////
    ///   UPDATE methods
    /** Saves an existing TaskCC in the database */
    public void save(TaskCC tcc) throws DataException {
        Connection conn = ConnectionPool.getInstance().get();
        try {
            save(tcc, conn);
            conn.commit();
        }catch (Exception e) {
            try{
            conn.rollback();
            }catch (SQLException e2) {
                throw new DataException("Could not roll back the database transaction!", e2);
            }
            throw new DataException("An error occurred while saving the business object information.", e);
        }finally {
            ConnectionPool.getInstance().release(conn);
        }
    }//update

    /** Internal method to update a TaskCC in the database */
    void save(TaskCC tcc, Connection conn) throws Exception {
        Cache.getInstance().put(tcc.getId(), tcc);
        if (tcc.isObjectAlreadyInDB() && tcc.isDirty()) {
            update(tcc, conn);
        }else if (tcc.isDirty()){
            insert(tcc, conn);
        }
    }//save

    /** Saves an existing TaskCC to the database */
    private void update(TaskCC tcc, Connection conn) throws Exception {
        PreparedStatement stmt = conn.prepareStatement("UPDATE Task_CC SET labortime=?, ID=?, ID=? WHERE ID=?");
        try {
            stmt.setDouble(1, tcc.getLabortime());
            stmt.setString(2, tcc.getTaskID());
            stmt.setString(3, tcc.getConcCarID());
            stmt.setString(4, tcc.getId());
            stmt.execute();
            tcc.setDirty(false);
        }finally{
            stmt.close();
        }
    }

    /** Inserts a new TaskCC into the database */
    private void insert(TaskCC tcc, Connection conn) throws Exception {
        PreparedStatement stmt = conn.prepareStatement("INSERT INTO Task_CC (ID, labortime, ID, ID) VALUES (?, ?, ?, ?)");
        try {
            stmt.setString(1, tcc.getId());
            stmt.setDouble(2, tcc.getLabortime());
            stmt.setString(3, tcc.getTaskID());
            stmt.setString(4, tcc.getConcCarID());
            stmt.execute();
            tcc.setObjectAlreadyInDB(true);
            tcc.setDirty(false);
        }finally{
            stmt.close();
        }
    }

    /////////////////////////////////////////////////
    ///   DELETE methods
    /** We do not support deleting of business objects in this application */
    public void delete(TaskCC tcc) throws DataException {
        throw new RuntimeException("Nice try. The delete function is not supported in this application.");
    }

    ////////////////////////////////////////////////
    ///   SEARCH methods
    /** Retrieves all TaskCCs from the database */
    public List<TaskCC> getAll() throws DataException {
        Connection conn = ConnectionPool.getInstance().get();
        try {
            PreparedStatement stmt = conn.prepareStatement("SELECT DISTINCT * FROM Task_CC ORDER BY ID");
            return search(stmt, conn);
        }catch (Exception e) {
            try{
            conn.rollback();
            }catch (SQLException e2) {
                throw new DataException("Could not roll back the database transaction!", e2);
            }
            throw new DataException("An error occurred while reading the business object information.", e);
        }finally {
            ConnectionPool.getInstance().release(conn);
        }
    }

    /** Retrieves Person by any inputted variable from the database */
    public List<TaskCC> readBy(String colName, String variable) throws DataException {
        Connection conn = ConnectionPool.getInstance().get();
        try {
            PreparedStatement stmt = conn.prepareStatement("SELECT DISTINCT * FROM Task_CC WHERE " + colName + "=? ORDER BY ID");
            stmt.setString(1, variable);
            return search(stmt, conn);
        }catch (Exception e) {
            try{
            conn.rollback();
            }catch (SQLException e2) {
                throw new DataException("Could not roll back the database transaction!", e2);
            }
            throw new DataException("An error occurred while reading the business object information.", e);
        }finally {
            ConnectionPool.getInstance().release(conn);
        }
    }

    /** Internal method to search by certain fields */
    private List<TaskCC> search(PreparedStatement stmt, Connection conn) throws Exception {
        List<TaskCC> tccs = new LinkedList<TaskCC>();
        try {
            ResultSet rs = stmt.executeQuery();
            while (rs.next()) {
                tccs.add(readRecord(rs, conn));
            }
        }finally{
            stmt.close();
        }
        return tccs;
    }
}